home *** CD-ROM | disk | FTP | other *** search
- /*
- * Bawk C actions builtin functions, variable declaration, and
- * stack management routines.
- */
- #include <stdio.h>
-
- #include "bawk.h"
-
- #define MAXARGS 10 /* max # of arguments to a builtin func */
- #define F_PRINTF 1
- #define F_GETLINE 2
- #define F_STRLEN 3
- #define F_STRCPY 4
- #define F_STRCMP 5
- #define F_TOUPPER 6
- #define F_TOLOWER 7
- #define F_MATCH 8
- #define F_NEXTFILE 9
-
- isfunction ( s )
- char *s;
- {
- /*
- * Compare the string "s" to a list of builtin functions
- * and return its (non-zero) token number.
- * Return zero if "s" is not a function.
- */
- if ( !strcmp( s, "printf" ) ) return F_PRINTF;
- if ( !strcmp( s, "getline" ) ) return F_GETLINE;
- if ( !strcmp( s, "strlen" ) ) return F_STRLEN;
- if ( !strcmp( s, "strcpy" ) ) return F_STRCPY;
- if ( !strcmp( s, "strcmp" ) ) return F_STRCMP;
- if ( !strcmp( s, "toupper" ) ) return F_TOUPPER;
- if ( !strcmp( s, "tolower" ) ) return F_TOLOWER;
- if ( !strcmp( s, "match" ) ) return F_MATCH;
- if ( !strcmp( s, "nextfile" ) ) return F_NEXTFILE;
- return 0;
- }
-
- iskeyword ( s )
- char *s;
- {
- /*
- * Compare the string "s" to a list of keywords and return its
- * (non-zero) token number. Return zero if "s" is not a keyword.
- */
- if ( !strcmp( s, "char" ) ) return T_CHAR;
- if ( !strcmp( s, "int" ) ) return T_INT;
- if ( !strcmp( s, "if" ) ) return T_IF;
- if ( !strcmp( s, "else" ) ) return T_ELSE;
- if ( !strcmp( s, "while" ) ) return T_WHILE;
- if ( !strcmp( s, "break" ) ) return T_BREAK;
-
- if ( !strcmp( s, "NF" ) ) return T_NF;
- if ( !strcmp( s, "NR" ) ) return T_NR;
- if ( !strcmp( s, "FS" ) ) return T_FS;
- if ( !strcmp( s, "RS" ) ) return T_RS;
- if ( !strcmp( s, "FILENAME" ) ) return T_FILENAME;
- if ( !strcmp( s, "BEGIN" ) ) return T_BEGIN;
- if ( !strcmp( s, "END" ) ) return T_END;
- return 0;
- }
-
- function ( funcnum ) {
- int argc, args[ MAXARGS ];
- char lpar;
-
- argc = 0;
- if ( Token==T_LPAREN ) {
- lpar = 1;
- getoken();
- }
- else lpar = 0;
- /*
- * If there are any arguments, evaluate them and copy their values
- * to a local array.
- */
- if ( Token!=T_RPAREN && Token!=T_EOF ) {
- for ( ;; ) {
- expression();
- if ( argc<MAXARGS ) args[ argc++ ] = popint();
- else popint();
- if ( Token==T_COMMA ) getoken();
- else break;
- }
- }
- if ( lpar && Token!=T_RPAREN ) error( "missing ')'", ACT_ERROR );
- else if ( Token==T_RPAREN ) getoken();
-
- switch ( funcnum ) {
- case F_PRINTF: /* just like the real printf() function */
- pushint( printf( args[0], args[1], args[2], args[3], args[4],
- args[5], args[6], args[7], args[8], args[9] ) );
- break;
- case F_GETLINE:
- /*
- * Get the next line of input from the current input file
- * and parse according to the current field seperator.
- * Don't forget to free up the previous line's words first...
- */
- while ( Fieldcount ) free( Fields[ --Fieldcount ] );
- pushint( getline() );
- Fieldcount = parse( Linebuf, Fields, Fieldsep );
- break;
- case F_STRLEN: /* calculate length of string argument */
- pushint( strlen( args[0] ) );
- break;
- case F_STRCPY: /* copy second string argument to first string */
- pushint( strcpy( args[0], args[1] ) );
- break;
- case F_STRCMP: /* compare two strings */
- pushint( strcmp( args[0], args[1] ) );
- break;
- case F_TOUPPER: /* convert the character argument to upper case */
- pushint( toupper( args[0] ) );
- break;
- case F_TOLOWER: /* convert the character argument to lower case */
- pushint( tolower( args[0] ) );
- break;
- case F_MATCH: /* match a string argument to a regular expression */
- pushint( match( args[0], args[1] ) );
- break;
- case F_NEXTFILE: /* close current input file and process next file */
- pushint( endfile() );
- break;
- default: /* oops! */
- error( "bad function call", ACT_ERROR );
- }
- }
-
- VARIABLE *
- findvar ( s )
- char *s;
- {
- /*
- * Search the symbol table for a variable whose name is "s".
- */
- VARIABLE *pvar;
- int i;
- char name[ MAXVARLEN ];
-
- i = 0;
- while ( i < MAXVARLEN && alphanum( *s ) ) name[i++] = *s++;
- if ( i<MAXVARLEN ) name[i] = 0;
-
- for ( pvar = Vartab; pvar<Nextvar; ++pvar ) {
- if ( !strncmp( pvar->vname, name, MAXVARLEN ) ) return pvar;
- }
- return NULL;
- }
-
- VARIABLE *
- addvar ( name )
- char *name;
- {
- /*
- * Add a new variable to symbol table and assign it default
- * attributes (int name;)
- */
- int i;
-
- if ( Nextvar <= Vartab + MAXVARTABSZ ) {
- i = 0;
- while ( i<MAXVARLEN && alphanum( *name ) )
- Nextvar->vname[i++] = *name++;
- if ( i<MAXVARLEN ) Nextvar->vname[i] = 0;
-
- Nextvar->vclass = 0;
- Nextvar->vsize = WORD;
- Nextvar->vlen = 0;
- /*
- * Allocate some new room
- */
- Nextvar->vptr = getmem( WORD );
- fillmem( Nextvar->vptr, WORD, 0 );
- }
- else error( "symbol table overflow", MEM_ERROR );
-
- return Nextvar++;
- }
-
- declist () {
- /*
- * Parse a "char" or "int" statement.
- */
- char type;
-
- type = Token;
- getoken();
- decl( type );
- while ( Token==T_COMMA ) {
- getoken();
- decl( type );
- }
- if ( Token==T_SEMICOLON ) getoken();
- }
-
- VARIABLE *
- decl ( type ) {
- /*
- * Parse an element of a "char" or "int" declaration list.
- * The function stmt_compile() has already entered the variable
- * into the symbol table as an integer, this routine simply changes
- * the symbol's class, size or length according to the declaraction.
- * WARNING: The interpreter depends on the fact that pointers are
- * the same length as int's. If your machine uses long's for
- * pointers either change the code or #define int long (or whatever).
- */
- char class, size;
- int len;
- unsigned oldsize, newsize;
- VARIABLE *pvar;
-
- if ( Token==T_MUL ) {
- /*
- * it's a pointer
- */
- getoken();
- pvar = decl( type );
- ++pvar->vclass;
- }
- else if ( Token==T_VARIABLE ) {
- /*
- * Simple variable so far. The token value (in the global
- * "Value" variable) is a pointer to the variable's symbol
- * table entry.
- */
- pvar = (VARIABLE *) Value.dptr;
- getoken();
- class = 0;
- /*
- * Compute its length
- */
- if ( Token==T_LBRACKET ) {
- /*
- * It's an array.
- */
- getoken();
- ++class;
- /*
- * Compute the dimension
- */
- expression();
- if ( Token!=T_RBRACKET ) error( "missing ']'", ACT_ERROR );
- getoken();
- len = popint();
- }
- else
- /*
- * It's a simple variable - array length is zero.
- */
- len = 0;
-
- size = (type==T_CHAR) ? BYTE : WORD;
-
- newsize = (len ? len : 1) * size;
- oldsize = (pvar->vlen ? pvar->vlen : 1) * pvar->vsize;
- if ( newsize != oldsize ) {
- /*
- * The amount of storage needed for the variable
- * has changed - free up memory allocated initially
- * and reallocate for new size.
- */
- free( pvar->vptr );
- pvar->vptr = getmem( newsize );
- }
- /*
- * Now change the variable's attributes.
- */
- pvar->vclass = class;
- pvar->vsize = size;
- pvar->vlen = len;
- }
- else syntaxerror();
-
- return pvar;
- }
-
- assignment () {
- /*
- * Perform an assignment
- */
- int ival;
-
- ival = popint();
- /*
- * make sure we've got an lvalue
- */
- if ( Stackptr->lvalue ) {
- if ( Stackptr->class ) movemem( &ival, Stackptr->value.dptr, WORD );
- else movemem(&ival, Stackptr->value.dptr, Stackptr->size);
- pop();
- pushint( ival );
- }
- else error( "'=' needs an lvalue", ACT_ERROR );
- }
-
- pop () {
- /*
- * Pop the stack and return the integer value
- */
- if ( Stackptr >= Stackbtm ) return (Stackptr--)->value.ival;
- return error( "stack underflow", ACT_ERROR );
- }
-
- push ( pclass, plvalue, psize, pdatum )
- char pclass, plvalue, psize;
- DATUM *pdatum;
- {
- /*
- * Push item parts onto the stack
- */
- if ( ++Stackptr <= Stacktop ) {
- Stackptr->lvalue = plvalue;
- Stackptr->size = psize;
- if ( !(Stackptr->class = pclass) && !plvalue )
- Stackptr->value.ival = pdatum->ival;
- else Stackptr->value.dptr = pdatum->dptr;
- }
- else error( "stack overflow", MEM_ERROR );
- }
-
- pushint ( intvalue )
- int intvalue;
- {
- /*
- * push an integer onto the stack
- */
- if ( ++Stackptr <= Stacktop ) {
- Stackptr->lvalue = Stackptr->class = 0;
- Stackptr->size = WORD;
- Stackptr->value.ival = intvalue;
- }
- else error( "stack overflow", MEM_ERROR );
- }
-
- popint () {
- /*
- * Resolve the item on the top of the stack and return it
- */
- int intvalue;
-
- if ( Stackptr->lvalue ) {
- /*
- * if it's a byte indirect, sign extend it
- */
- if ( Stackptr->size == BYTE && !Stackptr->class )
- intvalue = *Stackptr->value.dptr;
- else {
- /*
- * otherwise, it's an unsigned int
- */
- intvalue = (int) *Stackptr->value.ptrptr;
- }
- pop();
- return intvalue;
- }
- else {
- /*
- * else it's an ACTUAL, just pop it
- */
- return pop();
- }
- }